﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Wyn.PMS.Common.SecurityControl;
using Wyn.PMS.Entity.Entities;

namespace Wyn.PMS.Common.NightAudit
{
    /// <summary>
    /// 中央缓存控制台（考虑RADIS接口）
    /// <para>--------------------------</para>
    /// <para>@Author: cnalexi@gmail.com</para> 
    /// <para>@Create: 2011/5/22</para>  
    /// </summary>
    public class CacheMonitor
    {
        private static volatile CacheMonitor _instance;

        private static readonly object lockThis = new object();

        private static volatile RoomStatusCache roomStatusCache; 

        private static volatile RoomCountCache roomCountCache; 

        private static volatile CacheContainer cacheContainer; 

        private Thread _loopThread;

        private Thread _rescueThread;
        
        public const int RESCUE_CYCLE = 30; 
        
        private const int LIFETIME = 5;
        
        private static DateTime _expirationTime = DateTime.Now.AddMinutes(LIFETIME);
        
        private CacheMonitor()
        {
        }

        public static CacheMonitor GetInstance()
        {
            if (_instance == null)
            {
                lock (lockThis)
                {
                    if (_instance == null)
                    {
                        var monitor = new CacheMonitor();
                        
                        cacheContainer = CacheContainer.GetInstance();
                        
                        roomStatusCache = RoomStatusCache.GetInstance();
                        
                        roomCountCache = RoomCountCache.GetInstance();

                        monitor._rescueThread = new Thread(monitor.Rescue);
                        
                        Task.Factory.StartNew(BizCodeCache.CacheBizCode);

                        monitor.Sync();

                        _instance = monitor;

                        Thread.MemoryBarrier();
                    }

                }
            }
            return _instance;

        }

        public void Refresh()
        {
           
            cacheContainer.RefreshCache(null);

            
            roomStatusCache.Refresh(null);

            
            roomCountCache.Refresh();

        }

      
        public void Rescue()
        {
          
            cacheContainer.RefreshCache(DateTime.Now.AddSeconds(-RESCUE_CYCLE));
            
            if (DateTime.Now >= _expirationTime)
            {
                roomStatusCache.Refresh(DateTime.Now.AddMinutes(-LIFETIME));

                _expirationTime = DateTime.Now.AddMinutes(LIFETIME);
            }

            roomCountCache.Rescue(-RESCUE_CYCLE);

            if((DateTime.Now - BizCodeCache.LastDateTime).Days>1)
            {
                BizCodeCache.CacheBizCode();
            }
        }

        public void Sync()
        {
            if (IsMonitorDown)
            {
                return;
            }
            if (_loopThread != null)
            {
                try
                {
                    _loopThread.Abort();

                    Thread.Sleep(100);

                }
                catch (Exception ex)
                {
                    OperateLog.ErrorLog(ex.Message, ex);
                }

                if (_loopThread.IsAlive)
                {
                    throw new ThreadStateException("Can't Restart Cache Loop Thread");
                }
            }

            _loopThread = new Thread(Monitor)
            {
                Name = "CacheLoopThread",
                Priority = ThreadPriority.AboveNormal,
                IsBackground = true

            };

            _loopThread.Start();
        }
        
        public static bool IsMonitorDown { get; set; }

        public void Monitor()
        {
            int count = 0;

            int v = RESCUE_CYCLE; 

            while (true)
            {
                try
                {
                    Refresh();
                }
                catch (Exception error)
                {
                    OperateLog.ErrorLog(error.Message, error);
                }

                count = (count + 1) % v;

                if (count == v - 1)
                {
                    if (_rescueThread.ThreadState != ThreadState.Running)
                    {
                        _rescueThread = new Thread(Rescue)
                                            {
                                                Name = "CacheRescueThread",
                                                Priority = ThreadPriority.AboveNormal,
                                                IsBackground = true
                                            };
                        _rescueThread.Start();
                    }
                    
                }

                Thread.Sleep(1000);
            }
        }
        
        public DateTime GetLastModifiedTime(string hotelID)
        {
            return roomStatusCache.GetLastModifiedTime(hotelID);
        }

        public KeyValuePair<DateTime, IEnumerable<Room>> GetCacheRooms(DateTime lastRefreshTime, string hotelId)
        {

            return new KeyValuePair<DateTime, IEnumerable<Room>>(roomStatusCache.GetLastModifiedTime(hotelId),
                     roomStatusCache.GetCacheRooms(lastRefreshTime, hotelId));

        }

        public IEnumerable<Room> GetRooms(string hotelId, string roomTypeId)
        {
            DateTime initTimeStamp = DateTime.Parse("1984/11/09 18:00:00 PM");

            return roomStatusCache.GetCacheRooms(initTimeStamp, hotelId, roomTypeId);
        }

        public Room GetCacheRoom(string hotelId, string roomNo)
        {
            return roomStatusCache.GetRoom(hotelId, roomNo);
        }
        
    }
}
